package org.sixtynine.stock.service.file;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.sixtynine.stock.Constants;
import org.sixtynine.stock.ReturnData;
import org.sixtynine.stock.entity.AnnualShareData;
import org.sixtynine.stock.entity.BaseEntity;
import org.sixtynine.stock.entity.Company;
import org.sixtynine.stock.service.GenericService;
import org.sixtynine.stock.service.business.StockUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component(ExcelProcessorFactory.FILE_TYPE_ANNUAL_DATA_LIST)
public class AnnualDataProcesser extends CompanyDataListProcessor {

	int year;

	@Autowired
	GenericService genericService;

	private static Map<Integer, AnnualShareData> exsistingDataMap;
	private static Map<String, AnnualShareData> exsistingCompnayDataMap;

	public static String getDataString(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);

		return (calendar.get(Calendar.YEAR) + "_"
				+ calendar.get(Calendar.MONTH) + "_" + calendar
					.get(Calendar.DATE));
	}

	private static void processExsistingRecords(List<BaseEntity> dataList) {
		exsistingDataMap = new HashMap<Integer, AnnualShareData>();
		exsistingCompnayDataMap = new HashMap<String, AnnualShareData>();

		for (BaseEntity baseEntity : dataList) {
			AnnualShareData annualShareData = (AnnualShareData) baseEntity;
			exsistingDataMap.put(annualShareData.getYear(), annualShareData);
			exsistingCompnayDataMap.put(annualShareData.getCompany().getCode(),
					annualShareData);

		}
	}

	@Override
	public ReturnData<List<? extends BaseEntity>> process(String filePath) {
		ReturnData<List<? extends BaseEntity>> returnData = new ReturnData<List<? extends BaseEntity>>(
				Constants.SUCCESS, "");

		// initialized if maps are not created
		if (companyMap == null) {
			init();
		}

		try {

			List<AnnualShareData> annualShareDataList = new ArrayList<AnnualShareData>();
			File file = new File(filePath);

			// Get the workbook instance for XLS file
			Workbook workbook = WorkbookFactory.create(file);

			// Get first sheet from the workbook
			Sheet sheet = workbook.getSheetAt(0);

			// Get iterator to all the rows in current sheet
			Iterator<Row> rowIterator = sheet.iterator();
			int rowIndex = 0;

			String fileName = file.getName();

			String dteArry[] = fileName.split("_", 2);
			String dateS = dteArry[0];

			year = Integer.parseInt(dateS);

			// check file name
			if (!StockUtil.getFileName(fileName).equals(Constants.ANNUAL_DATA)) {
				returnData.setNo(Constants.ERROR);
				returnData.setMsg("Please add annual data only");
				return returnData;
			}

			Criterion criterion = (Restrictions.eq("year", year));
			List<BaseEntity> dataList = genericService.findByCriteria(
					criterion, AnnualShareData.class);
			if (dataList.size() > 0) {
				processExsistingRecords(dataList);
			}

			while (rowIterator.hasNext()) {
				AnnualShareData annualShareData = null;
				String companyCode = null;
				double netProfit = 0.00;
				double dividends = 0.00;
				double revenues = 0.00;
				double ebitda = 0.00;
				double weightAvaShare = 0.00;
				double recurringProfit = 0.00;
				double closingPrice = 0.00;
				double weightedAverageShareType = 0.00;
				double devidendOfShare = 0.00;

				Row row = rowIterator.next();
				// Get iterator to all cells of current row
				Iterator<Cell> cellIterator = row.cellIterator();

				if (rowIndex == 0) {
					Cell firstCell = row.getCell(0);
					if (firstCell == null) {
						returnData.setNo(Constants.ERROR);
						returnData
								.setMsg("Error file format, data should be started from first row and column");
						return returnData;
					}
					rowIndex++;
					continue;
				}

				int colIndex = 0;
				while (cellIterator.hasNext()) {
					Cell cell = cellIterator.next();
					Object cellVal = getCellValue(cell);
					switch (colIndex) {
					case 0:
						ReturnData<?> codeReturn = validateCompanyCode(cellVal,
								rowIndex);
						if (codeReturn._isSuccess()) {
							companyCode = (String) cellVal;
						} else {
							returnData.setNo(Constants.ERROR);
							returnData.setMsg(codeReturn.getMsg());
							return returnData;
						}
						break;
					case 1:
						break;

					case 2:
						dividends = (Double) cellVal;
						break;

					case 3:
						revenues = (Double) cellVal;
						break;

					case 4:
						ebitda = (Double) cellVal;
						break;

					case 5:
						weightAvaShare = (Double) cellVal;
						break;

					case 6:
						recurringProfit = (Double) cellVal;
						break;
					case 7:
						closingPrice = (Double) cellVal;
						break;
					case 8:
						weightedAverageShareType = (Double) cellVal;
						break;
					case 9:
						devidendOfShare = (Double) cellVal;
						break;

					default:
						break;
					}

					colIndex++;
				}

				Company company = companyMap.get(companyCode);
				if (company == null) {
					returnData.setNo(Constants.ERROR);
					returnData
							.setMsg("Company Code cannot find for company code "
									+ companyCode);
					return returnData;

				}

				if (dataList.size() > 0) {
					if (exsistingDataMap.containsKey(year)) {
						if (exsistingCompnayDataMap.containsKey(companyCode)) {
							annualShareData = exsistingDataMap.get(companyCode);
						} else {
							annualShareData = new AnnualShareData();
						}
					} else {
						annualShareData = new AnnualShareData();
					}
				} else {
					annualShareData = new AnnualShareData();
				}

				annualShareData.setCompany(company);
				annualShareData.setDividents(dividends);
				annualShareData.setEbitda(ebitda);
				annualShareData.setNetProfit(netProfit);
				annualShareData.setNumberOfShares(weightAvaShare);
				annualShareData.setRevenues(revenues);
				annualShareData.setRecurringProfit(recurringProfit);
				annualShareData.setYear(year);
				annualShareData.setClosingPrice(closingPrice);

				annualShareData.setAveShareOfShare(weightedAverageShareType);
				annualShareData.setDividenOfShare(devidendOfShare);

				annualShareDataList.add(annualShareData);

				rowIndex++;

			}

			returnData.setData(annualShareDataList);

		} catch (IOException e) {
			e.printStackTrace();
			returnData.setNo(Constants.ERROR);
			returnData.setMsg(e.getMessage());
		} catch (InvalidFormatException e) {
			e.printStackTrace();
			returnData.setNo(Constants.ERROR);
			returnData.setMsg(e.getMessage());
		}

		return returnData;
	}

	public int getFormattedYear(String fileName) throws Exception {
		int year = -1;
		String dteArry[] = fileName.split("_", 2);
		String dateS = dteArry[0];

		year = Integer.parseInt(dateS);

		return year;
	}

	private ReturnData<?> validateCompanyCode(Object cellVal, int row) {
		ReturnData<String> returnData = new ReturnData<String>(
				Constants.SUCCESS, "");

		if (!validateForNull(cellVal)) {
			returnData.setNo(Constants.ERROR);
			returnData.setMsg("Company code cannot be null at row " + row);
		}

		if (cellVal instanceof String) {
			String companyCode = (String) cellVal;

			// TODO validate format - with regular expression ?

		} else {
			returnData.setNo(Constants.ERROR);
			returnData.setMsg("Company code is in the wrong format at row "
					+ row);
		}

		return returnData;
	}

}
